package org.ssssssss.example.configuration;

import com.zaxxer.hikari.HikariDataSource;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.broadcast.config.BroadcastRuleConfiguration;
import org.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory;
import org.apache.shardingsphere.driver.api.yaml.YamlShardingSphereDataSourceFactory;
import org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
import org.apache.shardingsphere.infra.datasource.pool.creator.DataSourcePoolCreator;
import org.apache.shardingsphere.infra.datasource.pool.props.domain.DataSourcePoolProperties;
import org.apache.shardingsphere.shadow.yaml.config.datasource.YamlShadowDataSourceConfiguration;
import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableReferenceRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.strategy.audit.ShardingAuditStrategyConfiguration;
import org.apache.shardingsphere.sharding.api.config.strategy.keygen.KeyGenerateStrategyConfiguration;
import org.apache.shardingsphere.sharding.api.config.strategy.sharding.ComplexShardingStrategyConfiguration;
import org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
import org.apache.shardingsphere.sharding.spi.ShardingAlgorithm;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.ssssssss.example.interceptor.CustomRequestInterceptor;
import org.ssssssss.example.interceptor.CustomUIAuthorizationInterceptor;
import org.ssssssss.example.provider.*;
import org.ssssssss.example.scripts.CustomFunction;
import org.ssssssss.example.scripts.CustomFunctionExtension;
import org.ssssssss.example.scripts.CustomModule;
import org.ssssssss.magicapi.datasource.model.MagicDynamicDataSource;
import org.ssssssss.magicapi.modules.db.provider.PageProvider;

import javax.sql.DataSource;

/**
 * magic-api 配置类
 * 以下只配置了多数据源
 * 其它如果有需要可以自行放开 // @Bean 注释查看效果
 */
@Configuration
@Slf4j
public class MagicAPIConfiguration  implements WebMvcConfigurer {

	/**
	 * 配置多数据源
	 *
	 * @see org.ssssssss.magicapi.datasource.model.MagicDynamicDataSource
	 */
	@Bean
	public MagicDynamicDataSource magicDynamicDataSource() throws SQLException {
		MagicDynamicDataSource dynamicDataSource = new MagicDynamicDataSource();
		DataSource dataSource = getDataSource();
		dynamicDataSource.setDefault(dataSource); // 设置默认数据源
		dynamicDataSource.add("slave", dataSource);

		return dynamicDataSource;
	}
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/view/**")
			.addResourceLocations("classpath:/static/public/", "classpath:/static/js/");
	}

	/**
	 * 配置自定义JSON结果
	 */
	// @Bean
	public CustomJsonValueProvider customJsonValueProvider() {
		return new CustomJsonValueProvider();
	}

	/**
	 * 配置分页获取方式
	 */
	// @Bean
	public PageProvider pageProvider() {
		return new CustomPageProvider();
	}

	/**
	 * 自定义UI界面鉴权
	 */
	// @Bean
	public CustomUIAuthorizationInterceptor customUIAuthorizationInterceptor() {
		return new CustomUIAuthorizationInterceptor();
	}

	/**
	 * 自定义请求拦截器（鉴权）
	 */
	// @Bean
	public CustomRequestInterceptor customRequestInterceptor() {
		return new CustomRequestInterceptor();
	}

	/**
	 * 自定义SQL缓存
	 */
	// @Bean
	public CustomSqlCache customSqlCache() {
		return new CustomSqlCache();
	}

	/**
	 * 自定义函数
	 */
	// @Bean
	public CustomFunction customFunction() {
		return new CustomFunction();
	}

	/**
	 * 自定义方法扩展
	 */
	// @Bean
	public CustomFunctionExtension customFunctionExtension() {
		return new CustomFunctionExtension();
	}

	/**
	 * 自定义模块
	 */
	// @Bean
	public CustomModule customModule() {
		return new CustomModule();
	}

	/**
	 * 自定义脚本语言
	 */
	// @Bean
	public CustomLanguageProvider customLanguageProvider() {
		return new CustomLanguageProvider();
	}

	/**
	 * 自定义列名转换
	 */
	// @Bean
	public CustomMapperProvider customMapperProvider() {
		return new CustomMapperProvider();
	}


	// private DataSource buildDataSource() {
	// 	// 加载配置文件
	// 	YamlShadowDataSourceConfiguration shardingDataSource = (YamlShadowDataSourceConfiguration) YamlShadowDataSourceConfiguration.getDataSource("config.yaml");
	//
	// 	// 使用数据源进行数据库操作
	// 	try (Connection connection = shardingDataSource.getConnection()) {
	// 		// 执行SQL操作
	// 	} catch (SQLException e) {
	// 		e.printStackTrace();
	// 	}
	// }

	public DataSource getDataSource() throws SQLException {
		return ShardingSphereDataSourceFactory.createDataSource(createDataSourceMap(),
            Collections.singletonList(createShardingRuleConfiguration()), new Properties());
	}

	private ShardingRuleConfiguration createShardingRuleConfiguration() {
		ShardingRuleConfiguration result = new ShardingRuleConfiguration();
		Properties props = new Properties();
		props.setProperty("strategy", "standard");
		props.setProperty("algorithmClassName","org.ssssssss.example.configuration.MonthAlgorithm");

		result.getShardingAlgorithms().put("monthTableSharding", new AlgorithmConfiguration("MonthAlgorithm",props));
		result.getTables().add(getOrderTableRuleConfiguration());
		result.getBindingTableGroups().add(new ShardingTableReferenceRuleConfiguration("foo", "ledger_water"));
		// result.setDefaultDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("pay_time", "monthTableSharding"));
		// result.setDefaultTableShardingStrategy(new StandardShardingStrategyConfiguration("order_id", "standard_test_tbl"));

		// result.getShardingAlgorithms().put("standard_test_tbl", new AlgorithmConfiguration("STANDARD_TEST_TBL", new Properties()));
		// result.getKeyGenerators().put("snowflake", new AlgorithmConfiguration("SNOWFLAKE", new Properties()));
		// result.getAuditors().put("sharding_key_required_auditor", new AlgorithmConfiguration("DML_SHARDING_CONDITIONS", new Properties()));
		return result;
	}

	private ShardingTableRuleConfiguration getOrderTableRuleConfiguration() {
		ShardingTableRuleConfiguration result = new ShardingTableRuleConfiguration("ledger_water", "demo_ds_0.ledger_water_$->{2022..2099}$->{(1..12).collect(i->i.toString().padLeft(2,'0'))}");
		// result.setKeyGenerateStrategy(new KeyGenerateStrategyConfiguration("order_id", "snowflake"));
		// result.setAuditStrategy(new ShardingAuditStrategyConfiguration(Collections.singleton("sharding_key_required_auditor"), true));
		result.setTableShardingStrategy(new StandardShardingStrategyConfiguration("pay_time", "monthTableSharding"));
		return result;
	}


	private Map<String, DataSource> createDataSourceMap() {
		Map<String, DataSource> result = new HashMap<>();
		HikariDataSource dataSource = new HikariDataSource();
		dataSource.setUsername("root");
		dataSource.setPassword("sr4W(1fntqlE");
		dataSource.setJdbcUrl("jdbc:mysql://dev.base.c3lt.cn:3306/ledger?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false");
		result.put("demo_ds_0", dataSource);
		// result.put("demo_ds_1", DataSourceUtil.createDataSource("demo_ds_1"));
		return result;
	}

	private BroadcastRuleConfiguration createBroadcastRuleConfiguration() {
		return new BroadcastRuleConfiguration(Collections.singletonList("t_address"));
	}


}
